package jstella.cart;

import dolmisani.toys.emulators.j2600.cart.Cartridge;
import jstella.core.*;

/**
 * This is the cartridge class for Tigervision's bankswitched games. In this
 * bankswitching scheme the 2600's 4K cartridge address space is broken into two
 * 2K segments. The last 2K segment always points to the last 2K of the ROM
 * image. The desired bank number of the first 2K segment is selected by storing
 * its value into $3F. Actually, any write to location $00 to $3F will change
 * banks. Although, the Tigervision games only used 8K this bankswitching scheme
 * supports up to 512K.
 *
 * @author Bradford W. Mott
 * @version $Id: Cartridge3F.java,v 1.2 2007/08/18 09:10:38 mauvila Exp $
 */
public class Cartridge3F extends Cartridge {
    
    // Indicates which bank is currently active for the first segment
    private int currentBank;
    
    public Cartridge3F(byte[] imageBytes) {
        
        md5Digest = calculateMD5Digest(imageBytes);
        cartridgeImage = toIntArray(imageBytes);
    }

    @Override
    public void reset() {
        // We'll map bank 0 into the first segment upon reset
        setCurrentBank(0);
    }

    @Override
    public void install(JSSystem system) {
        
        this.system = system;
        //int shift = system.pageShift();
        //int mask = system.pageMask();

        // Make sure the system we're being installed in has a page size that'll work
        // assert((0x1800 & mask) == 0);

        // Set the page accessing methods for the hot spots (for 100% emulation
        // we need to chain any accesses below 0x40 to the TIA. Our poke() method
        // does this via system.tiaPoke(...), at least until we come up with a
        // cleaner way to do it.)
        //System::PageAccess access;
        addIndirectAccess(0x00, 0x40);  //Installing on zero page
 /* for(int i = 0x00; i < 0x40; i += (1 << shift))
         {
         access.directPeekBase = 0;
         access.directPokeBase = 0;
         access.device = this;
         system.setPageAccess(i >> shift, access);
         }
         */

        // Setup the second segment to always point to the last ROM slice
        addDirectPeekAccess(0x1800, 0x2000, cartridgeImage, 0x07FF, cartridgeImage.length - 2048);
        /*for(int j = 0x1800; j < 0x2000; j += (1 << shift))
         {
         access.device = this;
         access.directPeekBase = &image[(mySize - 2048) + (j & 0x07FF)];
         access.directPokeBase = 0;
         system.setPageAccess(j >> shift, access);
         }
         */

        // Install pages for bank 0 into the first segment
        setCurrentBank(0);
    }

    @Override
    public int peek(int address) {
        address = address & 0x0FFF;

        if (address < 0x0800) {
            return cartridgeImage[(address & 0x07FF) + currentBank * 2048];
        } else {
            return cartridgeImage[(address & 0x07FF) + cartridgeImage.length - 2048];
        }
    }

    public void poke(int address, int value) {
        address = address & 0x0FFF;

        // Switch banks if necessary
        if (address <= 0x003F) {
            setCurrentBank(value);
        }

        console.getTIA().poke(address, value); // ??
    }


    @Override
    protected void setCurrentBank(int bank) {
        if (bankLockedFlag == true) {
            return;
        }

        // Make sure the bank they're asking for is reasonable
        if (bank * 2048 < cartridgeImage.length) {
            currentBank = bank;
        } else {
            // Oops, the bank they're asking for isn't valid so let's wrap it
            // around to a valid bank number
            currentBank = bank % (cartridgeImage.length / 2048);
        }

        // int offset = myCurrentBank * 2048;
        // int shift = system.pageShift();

        // Setup the page access methods for the current bank
        // System::PageAccess access;
        //access.device = this;
        //access.directPokeBase = 0;

        // Map ROM image into the system
        addDirectPeekAccess(0x1000, 0x1800, cartridgeImage, 0x07FF, currentBank * 2048);
        /*for(int address = 0x1000; address < 0x1800; address += (1 << shift))
         {
         access.directPeekBase = &image[offset + (address & 0x07FF)];
         system.setPageAccess(address >> shift, access);
         }
         */
    }

    @Override
    protected int getCurrentBank() {
        return currentBank;
    }

    @Override
    protected int bankCount() {
        return cartridgeImage.length / 2048;
    }

    @Override
    public boolean patch(int address, int value) {
        address = address & 0x0FFF;
        if (address < 0x0800) {
            cartridgeImage[(address & 0x07FF) + currentBank * 2048] = value;
        } else {
            cartridgeImage[(address & 0x07FF) + cartridgeImage.length - 2048] = value;
        }
        return true;
    }

}
